%s	INELE INATTRS NORMAL INCOM INDT INATTRVAL

%{

/*
 * $Id: html.l,v 1.13 1995/03/20 16:11:16 chris Exp $
 */

#include <string.h>
#include "atom.h"
#include "dtd.h"
#include "html.h"
#include "y.tab.h"
static int first_time = 1;
static char quotechar = 0;

extern char *strdup();

/* For SGI lex */
#undef YYLMAX
#define YYLMAX 100 * 1024

extern HTMLErrorHandler _errorHandler;

%}


%%

%{
	if (first_time) {
	    BEGIN NORMAL;
	    first_time = 0;
	}
%}

<INATTRS>["']		{
			    /* Matches the beginning of double quoted string */
			    quotechar = *yytext;
			    BEGIN INATTRVAL;
			    if (quotechar == '"')
				return (ATTRDQUOTE);
			    else
				return (ATTRSQUOTE);
			}
<INATTRVAL>">"		{
			    /* Matches the end of a quoted string */
			    struct error err;
			    char buf[MAX_ERROR_LEN];

			    err.lineno = yylineno;
			    err.severity = E_SEVERE;
			    err.text = yytext;
			    err.type = E_MISSINGQUOTE;
			    err.message = buf;
			    sprintf(buf,
				    "Assuming attribute is missing an"
				    " ending quote.\n\tUse &gt; to embed"
				    " a greater than sign.");
			    _errorHandler(&err);

			    BEGIN INATTRS;
			    unput('>');		/* Save to terminate */
			    /* XXX Need error message */
			    if (quotechar == '"') {
				quotechar = 0;
				return (ATTRDQUOTE);
			    }
			    else if (quotechar == '\'') {
				quotechar = 0;
				return (ATTRSQUOTE);
			    }
			}
<INATTRVAL>["']		{
			    /* Matches the end of a quoted string */
			    if (*yytext == quotechar) {
				BEGIN INATTRS;
				if (quotechar == '"') {
				    quotechar = 0;
				    return (ATTRDQUOTE);
				}
				else if (quotechar == '\'') {
				    quotechar = 0;
				    return (ATTRSQUOTE);
				}
			    }
			    yylval.string = strdup(yytext);
			    return (STRING);
			}
<INATTRVAL>[^'"&>]+	{
			    /* Matches a string in quoted attribute value */
			    yylval.string = strdup(yytext);
			    return (STRING);
			}
<INATTRVAL>&		{
			    /*
			     * Matches & in quoted attribute value
			     */
			    yylval.string = strdup(yytext);
			    return (STRING);
			}

<INATTRVAL>&[#a-zA-Z0-9]+;	{
			    /* Matches an entity in quoted attribute value */
			    yylval.string = strdup(yytext);
			    return (ENTITY);
			}


<INATTRS>"="		{
			    /* Matches an equals sign while in a tag */
			    return (ATTREQUAL);
			}

<INATTRS>">"		{
			    /* Matches the end of a tag */
			    BEGIN NORMAL;
			    return (CLOSEGT);
			}
<INATTRS>[\n\r \t]	{
			    /* ignore whitespace */
			    ;
			}
<INATTRS>[^\n\r \t=>"']+	{
			    /* Matches other strings in a tag */
			    /* Note that \n \t = and > terminate a string */
			    yylval.string = strdup(yytext);
			    return (ATTRSTR);
			}

<INELE>[a-zA-Z0-9\.\-]+	{
			    /* Matches an element in the tag */
			    BEGIN INATTRS;
			    yylval.string = strdup(yytext);
			    return (ELEMENT);
			}
<INELE>.		{
			    /*
			     * Error checking for an illegal character
			     * starting an element name.  We could check
			     * in the above rule for errors but it seems
			     * to work better if we return a bogus
			     * attribute in that case.  We hope the user
			     * or parser could find it by inspection.
			     */
			    struct error err;
			    char buf[MAX_ERROR_LEN];

			    err.lineno = yylineno;
			    err.severity = E_SEVERE;
			    err.text = yytext;
			    err.type = E_UNEXPECTEDCHAR;
			    err.message = buf;
			    sprintf(buf,
				    "Illegal char %c (\\%o) starts"
				    " tag name",
				    yytext[0],
				    yytext[0]);
			    _errorHandler(&err);

			    exit (2);
			}

<INCOM>">"		{
			    /*
			     * Matches end of comment.
			     * This is the older style of broken comment.
			     */
			    BEGIN NORMAL;
			    return (ENDCOM);
			}

<INCOM>"-""-"*[ \t\n\r]*">"	{
			    /* Matches end of comment */
			    BEGIN NORMAL;
			    return (ENDCOM);
			}

<INCOM>(([^->])|("-"[^-]))*		{
			    /*
			     * WARNING: This is not working correctly
			     * on Solaris. XXX
			     */
			    /* Matches non '--' comment body */
			    yylval.string = strdup(yytext);
			    return (COMMENT);
			}
<INCOM>[-][-]		{
			    /* Matches '--' comment body */
			    yylval.string = strdup(yytext);
			    return (COMMENT);
			}

<INDT>">""\n"?		{
			    /* Matches end of doctype */
			    BEGIN NORMAL;
			    return (DTEND);
			}

<INDT>[^>]*		{
			    /* Matches body of doctype */
			    yylval.string = strdup(yytext);
			    return (DTBODY);
			}

<NORMAL>"<!"("DOCTYPE"|"doctype")	{
			    /* Matches start of doctype */
			    BEGIN INDT;
			    return (DTSTART);
			}

<NORMAL>"<!--"		{
			    /* Matches start of comment */
			    BEGIN INCOM;
			    yylval.lineno = yylineno;
			    return (STARTCOM);
			}
<NORMAL>"<"             {
			    /* Matches beginning of a start tag in text */
			    BEGIN INELE;
			    return (STARTTAG);
			}

<NORMAL>"</"		{
			    /* Matches beginning of an end tag in text */
			    BEGIN INELE;
			    return (ENDTAG);
			}

<NORMAL>"</>"		{
			    /* Matches short tag */
			    return (SHORTTAG);
			}

<NORMAL>[^<&]+		{
			    /* Matches a string in normal text */
			    yylval.string = strdup(yytext);
			    return (STRING);
			}
<NORMAL>"&"		{
			    /*
			     * Matches & in normal text
			     * &entity is matched below
			     */
			    yylval.string = strdup(yytext);
			    return (STRING);
			}

<NORMAL>("<"|"</")[^a-zA-Z!]	{
			    /* Matches a non-tag < */
			    yylval.string = strdup(yytext);
			    return (STRING);
			}

<NORMAL>"<inc"[\t\n\r ]	{
			    /*
			     * Matches an old style server include.
			     * We don't do anything with
			     * this line except pass it through
			     * as text.
			     */
			    yylval.string = strdup(yytext);
			    return (STRING);
			}
<NORMAL>"<!"		{
			    /*
			     * Matches some type of SGML value,
			     * not matched by comment or DOCTYPE
			     * lines.  We don't do anything with
			     * this line except pass it through
			     * as text.
			     */
			    yylval.string = strdup(yytext);
			    return (STRING);
			}

<NORMAL>&[#a-zA-Z0-9]+;	{
			    /* Matches an entity in normal text */
			    yylval.string = strdup(yytext);
			    return (ENTITY);
			}

.			{
			    /* This should probably never happen */
			    struct error err;
			    char buf[MAX_ERROR_LEN];

			    err.lineno = yylineno;
			    err.severity = E_SEVERE;
			    err.text = yytext;
			    err.type = E_UNEXPECTEDCHAR;
			    err.message = buf;
			    sprintf(buf,
				    "Illegal char '%c' (\\%o) in input",
				    yytext[0],
				    yytext[0]);
			    _errorHandler(&err);
			}

%%

int
yygetlineno()
{
    return (yylineno);
}


#ifdef notdef
<NORMAL>[\n \t]+	{
			    /*
			     * Right now we are trying to ignore white
			     * space strings in the input stream.
			     * This is a mistake because of the <PRE>
			     * mode.  We should probably pass it in
			     * as a special string token type and
			     * let the parser decide what to do with it.
			     */
			}
#endif
